const http = require('http');
const url = require('url');
const fs = require('fs');
const mime = require('mime')
//引入node.js中专门用来处理路径的模块
const path = require('path');
const querystring = require('querystring');
//用户信息列表
let users = [];
const handleRequest = (req, res) => {
    //使用node.js内置的url模块的parse方法解析url地址，返回一个对象
    //pathname路径名 query查询字符串,解析的时候第1个参数是要解析的url字符串，
    //第二个参数表示是否要把查询字符串转成对象并赋给query属性
    const { pathname, query } = url.parse(req.url, true);
    //如果请求的路径是/
    if (pathname === '/') {
        res.end('homepage');//返回一个homepage的字符串
        //如果请求的地址是/users
    } else if (pathname === '/users') {
        //判断请求的方法名，方法名不一样，想对用户列表这个资源的操作不一样
        switch (req.method) {
            case 'GET':
                //把users数组变成一个字符串，然后发给客户端
                //判断用户有没有把ID通过查询参数传递过来
                if(query.id){
                    //如果会传递了就通过ID到数组中查找对应的元素
                    let user = users.find(user=>user.id === Number(query.id));
                    //把此用户返回
                    res.end(JSON.stringify(user));
                }else{
                    //返回所有的用户
                    res.end(JSON.stringify(users));
                }
                break;
            case 'POST':
                //如果客户端请求的方法名是POST,意味着客户端希望添加一个用户
                getRequestBody(req).then((user) => {
                    //把此新的用户对象添加到数组里
                    users.push(user);
                    //向客户端返回新数组
                    //当你成功的创建一个新的资源，状态码是201
                    res.statusCode = 201;
                    res.end(JSON.stringify(users));
                });
                break;
            //如果客户端想删除一个用户的话，就就可发送DELETE方法
            case 'DELETE':
                //如果想删除 id为100的用户，对数组进行过滤，等于100的过滤掉，不等于100的留下
                users = users.filter(user => user.id !== Number(query.id));
                //把过滤后的新数组返回，写入响应体，返回给客户端
                res.end(JSON.stringify(users));
                break;
            case 'PUT':
                //先获取请求体
                getRequestBody(req).then((updateUser)=>{
                    console.log('updateUser',updateUser);
                    //映射老数组中的每一个用户对象
                    users=users.map(user=>{
                        //如果当前循环到的用户id和查询参数对象中的用户iD一样，说明这就是我要更新的用户对象
                        if(user.id === Number(query.id)){
                            return {
                                ...user,//展开老的用户对象
                                ...updateUser//展开更新的用户对象
                            }
                        }else{
                            return user;
                        }
                    });
                    res.end(JSON.stringify(users));
                })
                break;    
            default:
                break;
        }
    } else {
        //尝试读取静态文件
        //C:\aproject\zhufengjs\2.url\static\index.html
        //join用来连接路径
        //__dirname当前文件所有的绝对路径  C:\aproject\zhufengjs\2.url
        //static
        //pathname=/index.html
        //获取我们要读取的静态文件的绝对路径
        let filePath = path.join(__dirname,'static',pathname);
        //判断此路径上面的文件是否存在
        if(fs.existsSync(filePath)){
            //通过node内置的fs模块提供的读取文件的方法，把文件内容从硬盘上读出来，并按utf8编码转成字符串
            const fileContent = fs.readFileSync(filePath);
            //计算最新的etag值
            const newETag = fileContent.length;
            //跟客户端传过来If-None-Match字段进行比较 ，如果一样的话，说明内容未修改返回304，
            //如果不一样，说明修改过了，返回200
            //获取客户端传递过来的老的Etag值
            const oldEtag = req.headers['if-none-match'];
            //如果一样，说明文件未修改，可以直接返回304，不需要返回新的文件内容
            console.log(newETag , oldEtag) ;
            if(newETag == oldEtag){
                res.statusCode = 304;
                return res.end();
            }else{
                //从通过文件的路径获取文件的类型，然后再把此类型写入响应头中
                const fileType = mime.getType(filePath);
                res.setHeader('Content-Type',fileType);
                //添加响应头，开启强缓存
                res.setHeader('Cache-Control','max-age=10');
                res.setHeader('Etag',fileContent.length);
                //写入响应体,并结束响应
                res.statusCode = 200;
                res.end(fileContent);
            }
        }else{
            //如果不存在，则返回404的状态码，并且写入Not Found响应体
            res.statusCode = 404;
            res.end('Not Found');
        }
    }
};
function getRequestBody(req) {
    return new Promise((resolve) => {
        //先定义一个数组，用来存放客户端发过来的请求体
        //为什么是数组，因为客户端发送的数据可能很大，需要分块传输，需要持续不停的接收
        let buffers = [];
        //每当服务器收到客户端的一段数据就会执行回调
        //req.addEventListener('click',handleClick);
        req.on('data', (data) => {//data={"id":100, "name":"zhangsan"}
            //每收到一段数据就把数据放在数组中先暂时保存起来
            buffers.push(data);
        });
        //当客户端确认所有的数据都发完了，就会触发end事件
        req.on('end', () => {
            //先把Buffer 数组合并成一个大的Buffer
            const concatBuffer = Buffer.concat(buffers);//[{"id":100, "name":"zhangsan"}]
            //再通过toString把Buffer 转成字符串
            let body = concatBuffer.toString();
            //获取保存在请求头中的请求体的类型
            const contentType = req.headers['content-type']||'application/json';
            //如果传过来的请求体格式是一个表单字符串格式或者说是查询字符串的格式的话
            if(contentType === 'application/x-www-form-urlencoded'){
                //使用querystring把字符串转成对象
                resolve(querystring.parse(body));
            //如果内容类型是一个json格式的话    
            }else if(contentType === 'application/json'){
                //使用JSON.parse把字符串转成对象
                resolve(JSON.parse(body));
            }else{
                resolve(body);//'{id:100,name:'zhangsan'}'
            }
        });
    });
}
const server = http.createServer(handleRequest);
server.listen(8080, () => console.log('server is started on port 8080'));
// curl -X GET http://localhost:8080/
// curl -X GET http://localhost:8080/users